package com.butterfly.hotkey.sample.controller;

import cn.hutool.core.util.StrUtil;
import com.butterfly.hotkey.client.core.HotkeyStore;
import com.butterfly.hotkey.client.core.KeyValue;
import com.butterfly.hotkey.common.result.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * Client测试
 *
 * @author butterfly
 * @since 2025/2/17
 */
@RestController
@RequestMapping("/biz")
public class BizController {

    private static final Logger log = LoggerFactory.getLogger(BizController.class);
    @Resource
    private HotkeyStore hotkeyStore;

    @Value("${spring.application.name}")
    private String applicationName;

    @GetMapping("/detail")
    public Result<Object> getBizDetail(@RequestParam String id) {
        return Result.success(mutexGetValue(applicationName, id));
    }

    @GetMapping("/hotkey/{id}")
    public Result<Boolean> getKeyHot() {
        String applicationName = "sample";
        String cacheKey = buildCacheKey(applicationName, "1");
        boolean isHot = hotkeyStore.isHotKey(cacheKey);
        return Result.success(isHot);
    }

    /**
     * 互斥获取数据
     *
     * @return
     */
    private Object mutexGetValue(String applicationName, String id) {
        // 从缓存中获取数据
        String cacheKey = buildCacheKey(applicationName, id);
        KeyValue keyValue = hotkeyStore.getValue(cacheKey);

        // keyValue 不会为空, 可安全处理
        boolean hot = keyValue.isHot();

        // 缓存已有数据，直接返回
        if (hot && keyValue.getValue() != null) {
            return keyValue.getValue();
        }
        if (hot && keyValue.getValue() == null) {
            // 缓存无数据，需重新查询数据库，并放入缓存中
            // 使用同步锁保证只有一个线程去查询数据库, 分布式场景可增加分布式锁

            synchronized (cacheKey.intern()) {
                keyValue = hotkeyStore.getValue(cacheKey);
                if (keyValue.isHot() && keyValue.getValue() != null) {
                    return keyValue.getValue();
                }

                log.info("{} is hot,set cache value", cacheKey);
                Object result = getDbValue(id);
                hotkeyStore.cacheHotkey(cacheKey, result);
                return result;
            }
        }

        //并未hotkey，直接查询DB/redis
        synchronized (this) {
            return getDbValue(id);
        }
    }

    private Object getDbValue(String id) {
        return id;
    }

    private String buildCacheKey(String applicationName, String id) {
        return StrUtil.join(":", applicationName, "biz-key", id);
    }


}
